const express = require("express");
const router = express.Router();
const cors = require("cors");
const bodyParser = require("body-parser");
const fse = require("fs-extra");
const path = require("path");
const multipart = require("connect-multiparty");
const multer = require('multer');
const rateLimit = require('express-rate-limit');
const os = require('os');//引入os模块
const { TieziModel } = require('../model/model');

const multipartMiddleware = multipart();

// 所有上传的文件存放在该目录下
const UPLOADS_DIR = path.resolve("uploads");

// 配置 multer
// 创建一个multer存储引擎，用于处理文件上传
const storage = multer.diskStorage({
    // 设置文件上传的目录
    destination: function (req, file, cb) {
        // 将文件保存到UPLOADS_DIR目录下
        cb(null, UPLOADS_DIR);
    },
    // 设置文件上传后的文件名
    filename: function (req, file, cb) {
        // 将文件名设置为原始文件名
        cb(null, file.originalname);
    }
});

const upload = multer({ storage: storage });

// 初始限流配置
let directUploadConfig = {
    windowMs: 600 * 1000,
    max: 200,
    message: '直接上传请求过于频繁，请稍后再试'
};

let chunkUploadConfig = {
    windowMs: 600 * 1000,
    max: 800,
    message: '分片上传请求过于频繁，请稍后再试'
};

// 直接上传限流
let directUploadLimiter = rateLimit(directUploadConfig);

// 分片上传限流
let chunkUploadLimiter = rateLimit(chunkUploadConfig);

// 获取 CPU 使用率
// 获取CPU使用率
function getCpuUsage() {
    // 获取CPU信息
    const cpus = os.cpus();
    // 初始化空闲时间
    let idleTime = 0;
    // 初始化总时间
    let totalTime = 0;
    // 遍历每个CPU
    cpus.forEach((cpu) => {
        // 遍历每个CPU的时间类型
        for (const type in cpu.times) {
            // 累加总时间
            totalTime += cpu.times[type];
        }
        // 累加空闲时间
        idleTime += cpu.times.idle;
    });
    // 返回CPU使用率
    return (1 - (idleTime / totalTime));
}

// 动态调整限流规则
// 根据CPU使用率调整上传速率限制
// 调整上传速率限制
function adjustRateLimit() {
    // 获取CPU使用率
    const cpuUsage = getCpuUsage();
    // 如果CPU使用率小于0.3
    if (cpuUsage < 0.3) {
        // 直接上传最大限制为300
        directUploadConfig.max = 300;
        // 分块上传最大限制为1200
        chunkUploadConfig.max = 1200;
        // 如果CPU使用率小于0.7
    } else if (cpuUsage < 0.7) {
        // 直接上传最大限制为200
        directUploadConfig.max = 200;
        // 分块上传最大限制为800
        chunkUploadConfig.max = 800;
    } else {
        directUploadConfig.max = 100;
        chunkUploadConfig.max = 400;
    }
    // 根据配置创建直接上传速率限制器
    directUploadLimiter = rateLimit(directUploadConfig);
    // 根据配置创建分块上传速率限制器
    chunkUploadLimiter = rateLimit(chunkUploadConfig);
}

// 每隔一段时间检查 CPU 使用率并调整限流规则
setInterval(adjustRateLimit, 60 * 1000);

/**
 * 直接上传
 */
router.post("/directUpload", (req, res, next) => {
    directUploadLimiter(req, res, next);
}, upload.single('file'), async (req, res) => {
    const { inputContent, huatiId } = req.body
    console.log(inputContent, huatiId);
    const file = req.file;

    if (!file) {
        return res.status(400).send({
            success: false,
            msg: "未上传文件"
        });
    }
    const localDomain = `http://localhost:3000`;
    const filePath = path.join(UPLOADS_DIR, file.originalname);
    const fileUrl = `${localDomain}/server/download/${file.originalname}`;

    try {
        // 将文件名存入数据库
        await TieziModel.create({ content: inputContent, img: fileUrl, huatiId });
        res.send({
            code: 200,
            success: true,
            msg: "直接上传成功",
            data: {
                filePath,
                fileUrl
            }
        });
    } catch (error) {
        console.error('保存文件名到数据库时出错:', error);
        res.status(500).send({
            success: false,
            msg: '保存文件名到数据库时出错'
        });
    }
});

/**
 * 上传
 */
router.post("/upload", (req, res, next) => {
    chunkUploadLimiter(req, res, next);
}, multipartMiddleware, async (req, res) => {
    try {
        const { fileHash, chunkHash } = req.body;
        const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
        if (!fse.existsSync(chunkDir)) {
            await fse.mkdir(chunkDir);
        }
        const chunkPath = path.resolve(chunkDir, chunkHash);
        if (!fse.existsSync(chunkPath)) {
            await fse.move(req.files.chunk.path, chunkPath);
        }
        res.send({
            success: true,
            msg: "上传成功"
        });
    } catch (error) {
        console.error(error);
        res.status(500).send({
            success: false,
            msg: "上传分片时出现错误"
        });
    }
});

/**
 * 合并
 */
router.post("/merge", async (req, res) => {
    try {
        const { fileHash, fileName } = req.body;
        console.log('Received merge request with fileHash:', fileHash, 'and fileName:', fileName);

        if (!fileName || typeof fileName !== 'string' || fileName.includes('/') || fileName.includes('\\')) {
            console.log('Invalid file name received:', fileName);
            return res.status(400).json({
                success: false,
                msg: '无效的文件名'
            });
        }

        const filePath = path.resolve(UPLOADS_DIR, fileName);
        const chunkDir = path.resolve(UPLOADS_DIR, fileHash);

        const stats = await fse.stat(filePath).catch(() => null);
        if (stats && stats.isDirectory()) {
            console.log('The specified path is a directory:', filePath);
            return res.status(400).json({
                success: false,
                msg: '指定的路径是目录，无法合并文件'
            });
        }

        const chunkPaths = await fse.readdir(chunkDir);
        chunkPaths.sort((a, b) => parseInt(a.split("-")[1]) - parseInt(b.split("-")[1]));

        const writeStream = fse.createWriteStream(filePath);
        for (const chunkName of chunkPaths) {
            const chunkPath = path.resolve(chunkDir, chunkName);
            const readStream = fse.createReadStream(chunkPath);
            await new Promise((resolve, reject) => {
                readStream.pipe(writeStream, { end: false });
                readStream.on('end', resolve);
                readStream.on('error', reject);
            });
            await fse.unlink(chunkPath);
        }
        writeStream.end();

        const finalFileStats = await fse.stat(filePath).catch(() => null);
        if (!finalFileStats) {
            throw new Error('合并后的文件未成功创建');
        }

        if (await fse.pathExists(chunkDir)) {
            try {
                await fse.remove(chunkDir);
                console.log(`成功删除临时文件夹: ${chunkDir}`);
            } catch (removeError) {
                console.error(`删除临时文件夹 ${chunkDir} 时出错:`, removeError);
            }
        }

        const localDomain = `http://localhost:3000`;
        const fileUrl = `${localDomain}/server/download/${fileName}`;

        try {
            // 将文件名存入数据库
            await TieziModel.create({ img: fileUrl });
            res.json({
                success: true,
                msg: '合并成功',
                data: {
                    filePath,
                    fileUrl
                }
            });
        } catch (error) {
            console.error('保存文件名到数据库时出错:', error);
            res.status(500).json({
                success: false,
                msg: '保存文件名到数据库时出错'
            });
        }
    } catch (error) {
        console.error(error);
        res.status(500).json({
            success: false,
            msg: '合并文件时出现错误'
        });
    }
});

/**
 * 校验
 */
router.post("/verify", async (req, res) => {
    try {
        const { fileHash, fileName } = req.body;
        const filePath = path.resolve(UPLOADS_DIR, fileName);
        const existFile = await fse.pathExists(filePath);
        const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
        const existChunks = [];
        if (await fse.pathExists(chunkDir)) {
            existChunks.push(...await fse.readdir(chunkDir));
        }
        res.send({
            success: true,
            msg: "校验文件",
            data: {
                existFile,
                existChunks
            }
        });
    } catch (error) {
        console.error(error);
        res.status(500).send({
            success: false,
            msg: "校验文件时出现错误"
        });
    }
});

/**
 * 下载或查看文件
 */
router.get("/download/:fileName", async (req, res) => {
    const fileName = req.params.fileName;
    const filePath = path.resolve(UPLOADS_DIR, fileName);
    try {
        const exists = await fse.pathExists(filePath);
        if (!exists) {
            return res.status(404).send({
                success: false,
                msg: '文件不存在'
            });
        }
        const ext = path.extname(fileName).toLowerCase();
        const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif'];
        const videoExtensions = ['.mp4', '.webm', '.ogg'];
        const textExtensions = ['.txt', '.html', '.css', '.js'];

        if (imageExtensions.includes(ext)) {
            res.setHeader('Content-Type', `image/${ext.slice(1)}`);
            const readStream = fse.createReadStream(filePath);
            readStream.pipe(res);
        } else if (videoExtensions.includes(ext)) {
            res.setHeader('Content-Type', `video/${ext.slice(1)}`);
            const readStream = fse.createReadStream(filePath);
            readStream.pipe(res);
        } else if (textExtensions.includes(ext)) {
            res.setHeader('Content-Type', `text/${ext.slice(1) === 'js' ? 'javascript' : ext.slice(1)}`);
            const readStream = fse.createReadStream(filePath);
            readStream.pipe(res);
        } else {
            res.download(filePath, fileName, (err) => {
                if (err) {
                    console.error(err);
                    res.status(500).send({
                        success: false,
                        msg: '下载文件时出现错误'
                    });
                }
            });
        }
    } catch (err) {
        console.error(err);
        res.status(500).send({
            success: false,
            msg: '处理文件请求时出现错误'
        });
    }
});

module.exports = router;